/*
 * Copyright 2008-2009 Daniel Cachapa <cachapa@gmail.com>
 * 
 * This program is distributed under the terms of the GNU General Public Licence Version 3
 * The licence can be read in its entirety in the LICENSE.txt file accompaning this source code,
 * or at: http://www.gnu.org/copyleft/gpl.html
 * 
 * This file is part of WeightWatch.
 *
 * WeightWatch is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * WeightWatch is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the WeightWatch source code. If not, see
 * <http://www.gnu.org/licenses/>.
 */

package net.cachapa.weightwatch;

import net.cachapa.weightwatch.util.MyDate;
import java.util.Vector;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;

public class Database {
	private RecordStore recordStore;
	private static final String DB_NAME = "WeightWatchDB";
	private Vector database;

	public Database() {
		// Open or create the Record Store
		try {
			recordStore = RecordStore.openRecordStore(DB_NAME, true);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		database = new Vector();
		readDatabase();
	}

	public boolean addValue(Value value) {
		if (exists(value)) {
			return false;
		}
		try {
			byte[] valueData = value.toByteArray();
			int id = recordStore.addRecord(valueData, 0, valueData.length);
			value.dbIndex = id;
			database.addElement(value);
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		}
		sortDatabase();
		return true;
	}
	
	public void updateValue(Value value) {
		try {
			byte[] valueData = value.toByteArray();
			recordStore.setRecord(value.dbIndex, valueData, 0, valueData.length);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public Value getDay(int day, int month, int year) {
		MyDate searchedDate = new MyDate(day, month, year);
		Value value;
		int size = database.size();
		for (int i = 0; i < size; i++) {
			value = (Value)database.elementAt(i);
			if (value.date.equals(searchedDate)) {
				return value;
			}
		}
		return null;
	}

	public Value getLatestValue() {
		if (database.isEmpty()) {
			return new Value(new MyDate(), 0);
		}
		return (Value) database.lastElement();
	}
	
	/*
	 * Returns also the value just before the month and the value just after, if they exist
	 */
	public Vector getMonth(int month, int year) {
		Vector values = new Vector();
		Value value;
		value = getValueBefore(new MyDate(1, month, year));
		if (value != null) {
			values.addElement(value);
		}
		int size = database.size();
		for (int i = 0; i < size; i++) {
			value = (Value)database.elementAt(i);
			if (value.date.getMonth() == month && value.date.getYear() == year) {
				values.addElement(value);
			}
		}
		value = getValueAfter(new MyDate(MyDate.getDaysInMonth(month, year), month, year));
		if (value != null) {
			values.addElement(value);
		}
		return values;
	}
	
	/*
	 * Returns also the value just before the year and the value just after, if they exist
	 */
	Vector getYear(int year) {
		Vector values = new Vector();
		Value value;
		value = getValueBefore(new MyDate(1, 1, year));
		if (value != null) {
			values.addElement(value);
		}
		int size = database.size();
		for (int i = 0; i < size; i++) {
			value = (Value)database.elementAt(i);
			if (value.date.getYear() == year) {
				values.addElement(value);
			}
		}
		value = getValueAfter(new MyDate(31, 12, year));
		if (value != null) {
			values.addElement(value);
		}
		return values;
	}

	
	public Vector getValues() {
		return database;
	}
	
	public boolean exists(Value value) {
		Value otherValue;
		int size = database.size();
		for (int i = 0; i < size; i++) {
			otherValue = (Value)database.elementAt(i);
			if (value.date.getDay() == otherValue.date.getDay() &&
				value.date.getMonth() == otherValue.date.getMonth() &&
				value.date.getYear() == otherValue.date.getYear()) {
				return true;
			}
		}
		return false;
	}

	public int size() {
		return database.size();
	}

	void deleteValue(Value value) {
		try {
			recordStore.deleteRecord(value.dbIndex);
			database.removeElement(value);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public void deleteDatabase() {
		try {
			recordStore.closeRecordStore();
			RecordStore.deleteRecordStore(DB_NAME);
			recordStore = RecordStore.openRecordStore(DB_NAME, true);
			database.removeAllElements();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public Value getValueBefore(MyDate date) {
		Value value, prevValue = null;
		int size = database.size();
		for (int i = 0; i < size; i++) {
			value = (Value)database.elementAt(i);
			if (value.date.getTime()+1 > date.getTime()) {
				return prevValue;
			}
			prevValue = value;
		}
		return prevValue;
	}
	
	public Value getValueAfter(MyDate date) {
		Value value = null;
		int size = database.size();
		for (int i = 0; i < size; i++) {
			value = (Value)database.elementAt(i);
			if (value.date.getTime() > date.getTime() && !value.date.equals(date)) {
				return value;
			}
		}
		return null;
	}
	
	private void readDatabase() {
		int id;
		Value value;
		try {
			RecordEnumeration enumerator = recordStore.enumerateRecords(null, null, false);
			while (enumerator.hasNextElement()) {
				id = enumerator.nextRecordId();
				value = readValue(id);
				database.addElement(value);
			}
			enumerator.destroy();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		sortDatabase();
	}
	
	private Value readValue(int index) {
		Value value = null;
		try {
			byte[] data = recordStore.getRecord(index);
			value = new Value();
			value.fromByteArray(data);
			value.dbIndex = index;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return value;
	}
	
	private void sortDatabase() {
		QuickSorter.sort(database);
	}
}
